package com.desire.homework;

import java.util.EmptyStackException;
import java.util.Scanner;
import java.util.Stack;

/**
 * 求一个字符串表达式，计算结果
 * 1*6-3+1 = ?
 * 2*3/2-1=?
 * 1+2+3-5*2=?
 *
 * @author desire
 */
public class _46_计算一个数学式子 {
    public static void main(String[] args) {
        //System.out.println(Evaluate("(31 + 21) * 51 - (21 + 33) / 2 = "));
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入你要计算的表达式:");
        System.out.println(CaculateFunction.calculate(sc.next()));

    }

    public static class CaculateFunction {
        /**
         * 将传入的中缀表达式(即常见的运算式子) 转换为 后缀表达式
         *
         * @param IFX (中缀表达式)
         * @return PFX (后缀表达式)
         */
        private static String[] trnsInToSufix(String IFX)// PFX放后缀表达式，IFX为中缀表达式
        {
            if (!"=".equals(IFX.substring(IFX.length() - 1))) {
                IFX += "=";
            }
            String[] PFX = new String[IFX.length()];
            StringBuilder numBuffer = new StringBuilder();// 用来保存一个数的
            Stack<String> s = new Stack<>();// 放操作符
            String a;
            s.push("=");// 第一个为等号
            int i = 0, j = 0;
            char ch;
            for (i = 0; i < IFX.length(); ) {
                ch = IFX.charAt(i);
                switch (ch) {
                    case '0':
                    case '1':
                    case '2':
                    case '3':
                    case '4':
                    case '5':
                    case '6':
                    case '7':
                    case '8':
                    case '9':
                        while (Character.isDigit(ch) || ch == '.')// 拼数
                        {
                            numBuffer.append(ch); // 追加字符
                            ch = IFX.charAt(++i);
                        }
                        PFX[j++] = numBuffer.toString();// break;
                        numBuffer = new StringBuilder(); // 清空已获取的运算数字
                        continue; // 这里要重新循环，因为i已经增加过了
                    case '(':
                        s.push("(");
                        break;
                    case ')':
                        while (s.peek() != "(") {
                            PFX[j++] = s.pop();
                        }
                        break;
                    case '+':
                    case '-':
                        while (s.size() > 1 && s.peek() != "(") {
                            PFX[j++] = s.pop();
                        }
                        a = String.valueOf(ch);
                        s.push(a);
                        break;
                    case '*':
                    case '/':
                        while (s.size() > 1 && (s.peek() == "*") || s.peek() == "/"
                                || s.peek() == "s" || s.peek() == "c"
                                || s.peek() == "t" || s.peek() == "^"
                                || s.peek() == "√")
                        // 优先级比较，与栈顶比较，
                        {
                            PFX[j++] = s.pop();// 当前操作符优先级大于等于栈顶的弹出栈顶
                        }
                        a = String.valueOf(ch);
                        s.push(a);
                        break;
                    case 's':
                    case 'c':
                    case 't':// 三角函数
                        while (s.size() > 1
                                && (s.peek() == "s" || s.peek() == "c"
                                || s.peek() == "t" || s.peek() == "^" || s
                                .peek() == "√"))
                        // 优先级比较，与栈顶，大于等于的弹出
                        {
                            PFX[j++] = s.pop();
                        }
                        a = String.valueOf(ch);
                        s.push(a);
                        break;
                    case '^':// 幂
                    case '√':// 开方
                        while (s.size() > 1 && (s.peek() == "^" || s.peek() == "√")) {
                            PFX[j++] = s.pop();
                        }
                        a = String.valueOf(ch);
                        s.push(a);
                        break;
                    default:

                }
                i++;
            }
            while (s.size() > 1) {
                PFX[j++] = s.pop();
            }
            PFX[j] = "=";

            return PFX;
        }

        /**
         * 计算后缀表达式
         *
         * @param IFX 中缀表达式(普通的式子)
         * @return 式子计算结果
         */
        public static String calculate(String IFX)// 后缀表达式求值
        {
            String[] PFX = null;
            try {
                PFX = trnsInToSufix(IFX);
            } catch (EmptyStackException e) {
                return "表达式错误!";
            }
            // ↑  调用转换方法 trnsInToSufix 将表达式转换为后缀表达式 进行计算

            int i = 0;
            double x1, x2, n;
            String str;
            Stack<String> s = new Stack<>();
            while (PFX[i] != "=") {
                str = PFX[i];
                switch (str.charAt(0)) {
                    case '0':
                    case '1':
                    case '2':
                    case '3':
                    case '4':
                    case '5':
                    case '6':
                    case '7':
                    case '8':
                    case '9':
                        s.push(str);
                        break;
                    case '+':
                        x1 = Double.parseDouble(s.pop());
                        x2 = Double.parseDouble(s.pop());
                        n = x1 + x2;
                        s.push(String.valueOf(n));
                        break;
                    case '-':
                        x1 = Double.parseDouble(s.pop());
                        x2 = Double.parseDouble(s.pop());
                        n = x2 - x1;
                        s.push(String.valueOf(n));
                        break;
                    case '*':
                        x1 = Double.parseDouble(s.pop());
                        x2 = Double.parseDouble(s.pop());
                        n = x1 * x2;
                        s.push(String.valueOf(n));
                        break;
                    case '/':
                        x1 = Double.parseDouble(s.pop());
                        x2 = Double.parseDouble(s.pop());
                        n = x2 / x1;
                        s.push(String.valueOf(n));
                        break;
                    case 's':
                        x1 = Double.parseDouble(s.pop());
                        n = Math.sin(x1 * Math.PI / 180);
                        s.push(String.valueOf(n));
                        break;
                    case 'c':
                        x1 = Double.parseDouble(s.pop());
                        n = Math.cos(x1 * Math.PI / 180);
                        s.push(String.valueOf(n));
                        break;
                    case 't':
                        x1 = Double.parseDouble(s.pop());
                        n = Math.tan(x1 * Math.PI / 180);
                        s.push(String.valueOf(n));
                        break;
                    case '√':
                        x1 = Double.parseDouble(s.pop());
                        n = Math.sqrt(x1);
                        s.push(String.valueOf(n));
                        break;// 开方
                    case '^':
                        x1 = Double.parseDouble(s.pop());
                        x2 = Double.parseDouble(s.pop());
                        n = Math.pow(x2, x1);
                        s.push(String.valueOf(n));
                        break;
                    default:
                }
                i++;
            }
            return s.pop();
        }
    }
}
